package me.chenqiang.cinc;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import org.junit.Test;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;

import me.chenqiang.cinc.codes.ProvinceUtils;
import me.chenqiang.cinc.passportutils.CountryHuffmanCodec;
import me.chenqiang.cinc.passportutils.StringPrefixFreeCodecTrie;

public class PassportNumRelatedTestCase {
	@Test
	public void testSimple() {
		StringPrefixFreeCodecTrie<Integer> tree = new StringPrefixFreeCodecTrie<>();
		for(int i = 0; i < 256; i++) {
			tree.insert(String.format("%02x", i), i);
		}
		
		Random rnd = new Random();
		int rounds = rnd.nextInt(5, 10);
		StringBuffer sb = new StringBuffer();
		for(int i = 0; i < rounds; i ++) {
			sb.append(String.format("%02x", rnd.nextInt(0, 256)));
		}
		
		for(Entry<String, Integer> val: tree.items(sb)) {
			System.out.println(String.format("%s -> %d", val.getKey(), val.getValue()));
			assertEquals(String.format("%02x", val.getValue()), val.getKey());
		}
	}
	
	@Test
	public void testCountryCodec() {
		StringPrefixFreeCodecTrie<String> tree = new StringPrefixFreeCodecTrie<>();
		for(String key: CountryHuffmanCodec.CODEC_MAP.keySet()) {
			tree.insert(CountryHuffmanCodec.CODEC_MAP.get(key), key);
		}
		
		ArrayList<String> candidates = new ArrayList<>(CountryHuffmanCodec.CODEC_MAP.keySet());
		
		Random rnd = new Random();
		int rounds = rnd.nextInt(10, 20);
		StringBuffer sb = new StringBuffer();
		
		ArrayList<String> choices = new ArrayList<>();
		for(int i = 0; i < rounds; i ++) {
			String choice = candidates.get(rnd.nextInt(candidates.size()));
			choices.add(choice);
			sb.append(CountryHuffmanCodec.CODEC_MAP.get(choice));
		}
		
		System.out.println(String.join(",", choices));
		
		String encoded = sb.toString();
		System.out.println(encoded);
		
		ArrayList<String> decoded = new ArrayList<>();
		for(Entry<String, String> val: tree.items(encoded)) {
			System.out.println(String.format("%s -> %s", val.getKey(), val.getValue()));
			decoded.add(val.getValue());
		}
		
		System.out.println(String.join(",", decoded));
		
		assertEquals(String.join(",", choices), String.join(",", decoded));
	}
	
	@Test
	public void testPassportSamples() throws IOException {
		List<Entry<String, String>> samples = new ArrayList<>();
		try(InputStream jsonFile = ProvinceUtils.class.getResourceAsStream("/passport-samples.json")) {
			ObjectMapper mapper = new ObjectMapper();
			ArrayNode list = (ArrayNode)mapper.readTree(new InputStreamReader(jsonFile, StandardCharsets.UTF_8));
			for(JsonNode node: list) {
				ArrayNode tuple = (ArrayNode)node;
				samples.add(Map.entry(tuple.get(0).asText(), tuple.get(1).asText()));
			}
			
		} 
		
		for(Entry<String, String> item: samples) {
			try {
				String encoded = CincCoder.encodePassport(item.getKey(), item.getValue());
				System.out.println(String.format("%2s %9s -> %9s", item.getKey(), item.getValue(), encoded));
				String country = CincCoder.extractPassportIssuingCountry(encoded);
				assertEquals(country, item.getKey());
			}
			catch(CincCodingException cce) {
				cce.printStackTrace();
				continue;
			}
		}
	}
}
